//单例模式下固定线程数量的线程池
#pragma once

#include <iostream>
#include <cassert>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#include <sys/prctl.h>

#include "Log.hpp"
#include "Lock.hpp"
#include "Task.hpp"
using namespace std;

int gThreadNum = 5;//线程总数

template<class T>
class ThreadPool
{
private:
    ThreadPool(int threadNum = gThreadNum) : threadNum_(threadNum), isStart_(false)
    {
        assert(threadNum_ > 0);
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&cond_,nullptr);
    }

    ThreadPool(const ThreadPool<T> &) = delete;    //保证单例模式，禁用拷贝构造
    void operator=(const ThreadPool<T> &) = delete;             //禁用赋值运算
public:
    //静态成员，属于类但不属于创建出的对象，不带this指针
    static ThreadPool<T>* getInstance()  //生成一个实例
    {
        static Mutex mutex;  //整个线程池共用的静态互斥锁
        if(nullptr == instance)
        {
            LockGuard lockgurad(&mutex);    //进入代码块，加锁。退出代码块，自动解锁
            if(nullptr == instance)
            {
                instance = new ThreadPool<T>();
            }
        }

        return instance;
    }

    static void *threadRoutine(void *args)  //创建出的线程调用的方法
    {                                         //为了便于获取参数不受this指针影响
        pthread_detach(pthread_self());     //线程分离
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);//强转参数并接收
        prctl(PR_SET_NAME, "follower");     //修改当前线程名
        while (1)
        {
            tp->lockQueue();
            while (!tp->haveTask())
            {
                tp->waitForTask();  //没有任务就阻塞等待
            }
            //这个任务就被拿到了线程的上下文中
            T t = tp->pop();
            tp->unlockQueue();

            // for debug（Task.hpp）
            int one, two;
            char oper;
            t.get(&one, &two, &oper);
            //规定，所有的任务都必须有一个run方法
            Log() << "新线程完成计算任务: " << one << oper << two << "=" << t.run() << "\n";
        }
    }

    void start()  //提前创建好线程池内的线程，需要时调用（而不是临时再创建新线程）
    {
        assert(!isStart_);
        for(int i = 0;i <= threadNum_;i++)
        {
            pthread_t temp;
            pthread_create(&temp, nullptr, threadRoutine,this);
        }
        isStart_ = true;
    }

    void push(const T &in)
    {
        lockQueue();
        //以下为临界区访问
        taskQueue_.push(in);
        chioceThreadForHandle();
        //
        unlockQueue();
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }


private:
    void lockQueue() { pthread_mutex_lock(&mutex_); }
    void unlockQueue() { pthread_mutex_unlock(&mutex_); }
    bool haveTask() { return !taskQueue_.empty(); }
    void waitForTask() { pthread_cond_wait(&cond_, &mutex_); }   //条件变量等待
    void chioceThreadForHandle() { pthread_cond_signal(&cond_); }//唤醒条件变量
    
    T pop()    //出队列顶元素
    {
        T temp = taskQueue_.front();
        taskQueue_.pop();

        return temp;
    }

private:
    bool isStart_;
    int threadNum_;
    queue<T> taskQueue_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;

    static ThreadPool<T> *instance;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::instance = nullptr;